#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2023/11/26 20:40
# @Author  : 新猿异码
# @Site    : https://gitee.com/chshao/autotest
# @CSDN    : https://blog.csdn.net/m0_37576542?type=blog
# @File    : TestRunner.py
# @Desc    : 模块功能描述
# @Software: PyCharm
import os
import re
import time
from autotest.kernel.logger import AutoLogging
from autotest.kernel.logger.AutoLogging import Log
from autotest.kernel.modle.Variable import Var
from autotest.kernel.modle.HookImpl import HookImpl
from autotest.kernel.modle import Constants, CException


# 处理异常的装饰器
def except_wrapper(func):
    def _inner(*args, **kwargs):
        try:
            ret = func(*args, **kwargs)
            return ret
        except:
            Log.traceback()
            return False

    return _inner


class TestRunner(object):

    @staticmethod
    def run(suite: list):
        for testcase in suite:
            Log.info("----------------------Next TestCase----------------------")
            Log.info(f">>>Start Run TestCase: {testcase}")
            testcase_split = testcase.split(".")
            testcase_module = ".".join(testcase_split[:-2])
            testcase_class = testcase_split[-2]
            testcase_method_param = testcase_split[-1]

            Var.Case.CaseID = testcase_split[-1]
            Var.Case.Module = ".".join(testcase_split[1:-1])
            Var.Case.StartTime = time.strftime("%Y-%m-%d %H:%M:%S")
            Var.Case.Marker = Var.Suite.get(testcase_method_param.split("[")[0], {}).get("marker")
            Var.Case.Desc = Var.Suite.get(testcase_method_param.split("[")[0], {}).get("desc", "")
            Var.Case.CaseResult = Constants.CASE_RUNNING
            Var.Case.Detail = ""
            # 添加用例级别日志记录
            AutoLogging.addCaseLog()

            _instance = TestRunner.__run_testcase_init(testcase_module, testcase_class)
            if _instance:
                reruns = Var.Suite.get(testcase_method_param.split("[")[0], {}).get("reruns", 0)
                for rerun in range(reruns + 1):  # 支持失败重跑
                    if rerun > 0:
                        Log.info(f">>>Start Rerun TestCase: {testcase}")
                    if TestRunner.__run_testcase_setup(_instance):
                        Log.info(f"**{testcase} setup: Passed")
                        if TestRunner.__run_testcase_method(_instance, testcase_method_param):
                            Var.Case.CaseResult = Constants.CASE_PASSED
                            Log.info(f"**{testcase} Run Result: Passed")
                        else:
                            Log.error(f"**{testcase} Run Result: Failed")
                            Var.Case.CaseResult = Constants.CASE_FAILED
                    else:
                        Log.error(f"**{testcase} setup: Failed")
                        Var.Case.CaseResult = Constants.CASE_FAILED
                    if TestRunner.__run_testcase_teardown(_instance):
                        Log.info(f"**{testcase} teardown: Passed")
                    else:
                        Log.error(f"**{testcase} teardown: Failed")
                    # 用例执行Pass则不需要失败重跑，立即跳出循环
                    if Var.Case.CaseResult == Constants.CASE_PASSED:
                        break
            else:
                Log.error(f"**{testcase} Run Result: Block")
                Var.Case.CaseResult = Constants.CASE_BLOCK

            Var.Case.EndTime = time.strftime("%Y-%m-%d %H:%M:%S")
            Var.Project[Var.Case.CaseResult] += 1
            # 移除用例级别日志记录
            AutoLogging.removeCaseLog()
            # 将用例执行结果写入本地.db文件
            TestRunner.write_testcase_result_to_db()
            TestRunner.update_task_msg_to_db()
            # 调用用例数据入库钩子函数
            HookImpl.write_testcase_database(Var.Case)

    @staticmethod
    @except_wrapper
    def __run_testcase_init(module_path, class_name):
        module_name = module_path.split('.')[-1]
        module = __import__(module_path, fromlist=[module_name])
        return getattr(module, class_name)()

    @staticmethod
    @except_wrapper
    def __run_testcase_setup(obj) -> bool:
        getattr(obj, "setup_start")()
        getattr(obj, "setup")()
        getattr(obj, "setup_end")()
        return True

    @staticmethod
    @except_wrapper
    def __run_testcase_method(obj, method_param) -> bool:
        method_param_split = method_param.split("[")
        method = method_param_split[0]
        if "[" in method_param:
            param = None
            param_str = method_param_split[1][:-1]
            datas = Var.Suite[method]["datas"]
            # 参数化传进来的是一个function时
            if callable(datas):
                datas = datas()
            for data in datas:
                if param_str == str(data):
                    param = data
                    break
            if param is None:
                Var.Case.CaseResult = Constants.CASE_BLOCK
                raise CException.NoTestCaseException(f"has no this testcase: {method_param}")
            getattr(obj, method)(param)
        else:
            getattr(obj, method)()
        return True

    @staticmethod
    @except_wrapper
    def __run_testcase_teardown(obj) -> bool:
        getattr(obj, "teardown_start")()
        getattr(obj, "teardown")()
        getattr(obj, "teardown_end")()
        return True

    @staticmethod
    def write_testcase_result_to_db():
        run_log_msg = ""
        log_file = os.path.join(Var.Project.ReportPath, 'log', Var.Case.CaseID, f"{Var.Case.CaseID}.log")
        if os.path.exists(log_file):
            with open(log_file, 'r', encoding='utf8') as rf:
                run_log_msg = rf.read()
        from autotest.kernel.modle.TestModel import TestCase
        TestCase.insert(task_id=Var.Project.TaskId,
                        case_id=Var.Case.CaseID,
                        module=Var.Case.Module,
                        start_time=Var.Case.StartTime,
                        end_time=Var.Case.EndTime,
                        result=Var.Case.CaseResult,
                        detail=Var.Case.Detail,
                        run_log=run_log_msg,
                        desc=Var.Case.Desc).execute()

    @staticmethod
    def update_task_msg_to_db():
        from autotest.kernel.modle.TestModel import Task
        not_run = Var.Project.Total - Var.Project.Passed - Var.Project.Failed - Var.Project.Block
        pass_rate = 0
        if Var.Project.Total > 0:
            pass_rate = round(100 * Var.Project.Passed / Var.Project.Total, 2)
        Task.update(end_time=time.strftime('%Y-%m-%d %H:%M:%S'),
                    passed=Var.Project.Passed,
                    failed=Var.Project.Failed,
                    block=Var.Project.Block,
                    not_run=not_run,
                    pass_rate=pass_rate
                    ).where(task_id=Var.Project.TaskId).execute()


if __name__ == '__main__':
    _pattern = re.compile("(预置条件:|测试步骤:|检查点:|后置操作:).*")
    a=_pattern.search("hhuu 测试步骤: khihionjhuii你好")
    print(type(a.group()))
